<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // 参考文章:https://www.cnblogs.com/youhong/p/12218661.html
      //js面试题：https://www.toptal.com/javascript/interview-questions
			debugger;
      function bar() {
        var a = 1;
        function foo() {
          console.log(a);
        }
        foo();
      }
      bar();
      //打开控制台会执行的时候有个闭包Closure,这个闭包Closure表示，当bar的执行上下文被销毁后（此时bar已经执行完毕），foo的作用域链为[Local, Closure(bar), Global]，也就是说此时foo仍然能访问到bar函数内的变量a
       //在 JavaScript 中，根据词法作用域的规则，内部函数总是可以访问其外部函数中声明的变量，即内部函数的作用域链上会存在这些变量的结合，即使外部函数执行结束也不会改变内部函数的作用域链，也就是这些变量依然会保存在内存中，我们把这个变量的集合就是闭包
      //闭包就是内部函数对外部函数变量的一个引用集合，所以当内部函数没有用到外部函数的变量，那内部函数的作用域链上也就不需要有外部函数了
      
       // debugger;
      function createFunctions() {
        var result = new Array();
        for (var i = 0; i < 3; i++) {
          result[i] = function () {
            return i;
          };
        }
        return result;
      }
      var funcList = createFunctions();
      console.log(funcList[0]()); //3
      console.log(funcList[1]()); //3
      console.log(funcList[2]()); //3
      // 上面的例子中，result数组的每一项的作用域链都是 [Local,Closure(createFunctions),Global]
      // 而每一项的Closure(createFunctions)是共享的，也就是当createFunctions函数执行完，此时createFunctions中的i的值为3了
      // ，所以当执行result数组的任一项时，根据作用域链查找就会查到Closure(createFunctions)里的i，此时i为3，所以就都打印出了3
      //如何能输出0,1,2？通过创建一个匿名函数的方式加一个闭包
      debugger;
      function createFunctions() {
        var result = new Array();
        for (var i = 0; i < 3; i++) {
          result[i] = (function (num) {
            return function () {
              return num;
            };
          })(i);
        }
        return result;
      }
      var funcList = createFunctions();
      console.log(funcList[0]());
      console.log(funcList[1]());
      console.log(funcList[2]());
      // 加了一层闭包后，result数组里各项函数的作用域链就变为了
      // result[0]
      [Local, Closure({ num: 0 }), Global][
        // result[1]
        (Local, Closure({ num: 1 }), Global)
      ][
        // result[2]
        (Local, Closure({ num: 2 }), Global)
      ];
      // 也就是此时各项函数作用域链里的闭包均是单独创建的，是相互独立的三个不同闭包，并且也独立与createFunctions的作用域。
      // 所以当createFunctions执行完后，createFunctions里的i同样是3，但已经不会影响到result数组里的各项函数了。
      // 这些函数在执行时，都会顺着自己的作用域链找到相应的Closure，并返回其中的变量num的值
    </script>
  </body>
</html>
